{
 "cells": [
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 量子金融投资组合优化简介\n",
    "*Copyright (c) 2022 Institute for Quantum Computing, Baidu Inc. All Rights Reserved.*\n",
    "\n",
    "假如你是一位资产管理人，想要将数额为$K$的基金一次性投入到$N$个可投资的项目中，各项目都有自己的投资回报率和风险，你的目标就是在考虑到市场影响和交易费用的的基础上找到一个最佳的投资组合，使得该笔资产以最优的投资方案实施。\n",
    "\n",
    "为了方便建模，我们做如下两点假设：\n",
    "    1.每个项目都是等额投资的；\n",
    "    2.给定的预算是投资一个项目金额的整数倍，且必须全部花完。\n",
    "\n",
    "在投资组合的基本理论中，投资组合的总体风险与项目间的协方差有关，而协方差与任意两项目的相关系数成正比。相关系数越小，其协方差就越小，投资组合的总体风险也就越小。在这里我们给出了采用均值方差组合优化的方法下的该问题的建模方程：\n",
    "$$\n",
    "\\omega=\\max _{x \\in\\{0,1\\}^n} \\mu^T x-q x^T S x \\quad \\text { subject to: } 1^T x=B,\n",
    "$$\n",
    "该式子中各符号代表的含义如下：\n",
    "- $x \\in \\{0, 1\\}^{n}$ 表示一个向量，其中每一个元素均为二进制变量，即如果资产$i$被投资了，则 $x_i$=1，如果没有被选择，则 $x_i=0$；\n",
    "- $\\mu \\in \\mathbb{R}^n$ 表示投资每个项目的预期回报率；\n",
    "- $S \\in \\mathbb{R}^{n \\times n}$ 表示各投资项目回报率之间的协方差矩阵；\n",
    "- $q > 0$ 表示做出该投资决定的风险系数；\n",
    "- $B$ 代表投资预算,即我们可以投资的项目数。\n",
    "\n",
    "让我们对这个方程的含义进行说明。$\\mu^T x$ 刻画 $x$ 代表的投资方案的预期收益。$x^T S x$ 刻画投资项目之间的关联性，乘上风险系数 $q$ 之后，代表该投资方案包含的风险。$1^T x=B$ 要求我们投资的项目数等于我们的预算总数。因此，当我们对所有的投资方案寻找等式右边的最大值，得到的 $\\omega$ 就是我们理论上可以得到的最大收益。\n",
    "\n",
    "为了方便寻找使收益最大化的投资组合，我们定义如下的损失函数：\n",
    "$$\n",
    "C_x=q \\sum_i \\sum_j S_{j i} x_i x_j-\\sum_i x_i \\mu_i+A\\left(B-\\sum_i x_i\\right)^2,\n",
    "$$\n",
    "其中，约束条件以拉格朗日乘子的形式进入方程。于是，我们的任务转化成寻找使损失函数最小的$x$。"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 量子编码及求解\n",
    "我们通过变换 $x_i \\mapsto \\frac{I-Z_i}{2}$ 将损失函数转为一个哈密顿量，从而完成投资组合优化问题的编码。这里$Z_i=I \\otimes I \\otimes \\ldots \\otimes Z \\otimes \\ldots \\otimes I$，即 $Z_{i}$ 是作用在第$i$ 个比特上的Pauli算符。我们用这个映射将 $C_x$ 转化成量子比特数为 $n$ 的系统的哈密顿矩阵 $H_C$，其基态即为投资组合优化问题的最优解。为了寻找这一哈密顿量的基态，我们使用变分量子算法的思想，通过一个参数化量子线路，生成一个试验态 $|\\theta^* \\rangle$。我们通过量子线路获得哈密顿量在该试验态上的期望值，然后，通过经典的梯度下降算法调节参数化量子线路的参数，使期望值向基态能量靠拢。重复若干次之后，我们找到最优解：\n",
    "$$\n",
    "|\\theta^* \\rangle  = \\arg\\min_\\theta L(\\vec{\\theta})=\\arg\\min_\\theta \\left\\langle\\vec{\\theta}\\left|H_C\\right| \\vec{\\theta}\\right\\rangle.\n",
    "$$\n",
    "最后，我们读出测量结果的概率分布：$p(z)=\\left|\\left\\langle z \\mid \\vec{\\theta}^*\\right\\rangle\\right|^2$，即由量子编码还原出原先比特串的信息。某个比特串出现的概率越大，意味着其是投资组合优化问题最优解的可能性越大。"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 使用教程\n",
    "### 配置文件\n",
    "我们给出了一个设置好参数，可以直接进行组合优化计算的配置文件。用户只需在`config.toml`里修改相应的参数，并在终端运行\n",
    "`python qpo.py --config config.toml --logger qpo_log.log`，即可计算最优投资组合。\n",
    "### 输出结果\n",
    "运行结果将输出到文件 `qpo_log.log` 中。我们的优化过程将被记录在日志中。用户可以看到随着循环数的增加，损失大小的变化。最后我们会输出优化得到的方案选择。\n",
    "\n",
    "### 参数说明\n",
    "- `stock`，默认为 `'demo'`，即使用我们提供的样本数据。也可选 `'random'` 或 `'custom'` 来随机生成或使用自定义数据。\n",
    "若用户选择随机生成数据，用户可以通过修改 `start_time` 和 `end_time` 参数来选择股票数据的起止日期。对于自定义数据，用户可以使用格式和表头命名规则（即 `csv` 文件的第一行）与 `demo_stock.csv` 文件相同的自定义文件，并在配置文件修改该文件路径："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "custom_data_path = 'file_name.csv'"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 在线演示\n",
    "这里，我们给出一个在线演示的版本，可以在线进行测试。首先定义配置文件的内容："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "config_toml = r\"\"\"\n",
    "# 用于计算金融组合优化问题模型的整体配置文件。\n",
    "# 使用样例股票数据\n",
    "stock = 'demo' \n",
    "demo_data_path = 'demo_stock.csv'\n",
    "# 可投资项目的数目\n",
    "num_asset = 7\n",
    "# 决策风险系数\n",
    "risk_weight = 0.5\n",
    "# 投资预算\n",
    "budget = 0\n",
    "# 投资惩罚\n",
    "penalty = 0\n",
    "# 量子电路深度\n",
    "circuit_depth = 2\n",
    "# 优化循环次数\n",
    "iterations = 600\n",
    "# 梯度下降优化的学习速率\n",
    "learning_rate = 0.2 \n",
    "\"\"\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "量桨 PaddleQuantum 的金融模块实现了量子金融优化的数值模拟。我们可以从 ``paddle_quantum.finance.qpo`` 模块里导入 ``portfolio_combination_optimization`` 来解决配置好的金融组合优化问题。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "100%|██████████| 600/600 [01:15<00:00,  7.93it/s]\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "******************* 最优组合为： [2, 5, 6]  *******************\n"
     ]
    }
   ],
   "source": [
    "import os\n",
    "import warnings\n",
    "warnings.filterwarnings(\"ignore\")\n",
    "os.environ['PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION'] = 'python'\n",
    "import pandas as pd\n",
    "\n",
    "import toml\n",
    "from paddle_quantum.finance.qpo import portfolio_combination_optimization\n",
    "from paddle_quantum.finance import DataSimulator\n",
    "\n",
    "config = toml.loads(config_toml)\n",
    "demo_data_path = config[\"demo_data_path\"]\n",
    "num_asset = config[\"num_asset\"]\n",
    "risk_weight = config[\"risk_weight\"]\n",
    "budget = config[\"budget\"]\n",
    "penalty = config[\"penalty\"]\n",
    "circuit_depth = config[\"circuit_depth\"]\n",
    "iterations = config[\"iterations\"]\n",
    "learning_rate = config[\"learning_rate\"]\n",
    "\n",
    "stocks_name = [(\"STOCK%s\" % i) for i in range(num_asset)]\n",
    "source_data = pd.read_csv(demo_data_path)\n",
    "processed_data = [source_data['closePrice'+str(i)].tolist() for i in range(num_asset)]\n",
    "data = DataSimulator(stocks_name)\n",
    "data.set_data(processed_data)\n",
    "\n",
    "invest = portfolio_combination_optimization(num_asset, data, iterations, learning_rate, risk_weight, budget,\n",
    "                                       penalty, circuit=circuit_depth)\n",
    "print(f\"******************* 最优组合为： {invest}  *******************\")\n"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "## 注意事项\n",
    "若投资方案数较小（`num_asset`$< 12$），我们可以通过严格对角化哈密顿量来计算真实的损失最小值，并与优化的结果比较。若二者的差别较大，该优化结果不可靠，需要重新选择训练参数。\n",
    "## 相关论文以及引用信息\n",
    "```\n",
    "@article{ORUS2019100028,\n",
    "title = {Quantum computing for finance: Overview and prospects},\n",
    "journal = {Reviews in Physics},\n",
    "volume = {4},\n",
    "pages = {100028},\n",
    "year = {2019},\n",
    "issn = {2405-4283},\n",
    "doi = {https://doi.org/10.1016/j.revip.2019.100028},\n",
    "url = {https://www.sciencedirect.com/science/article/pii/S2405428318300571},\n",
    "author = {Román Orús and Samuel Mugel and Enrique Lizaso}\n",
    "}\n",
    "\n",
    "@ARTICLE{2020arXiv200614510E,\n",
    "       author = {{Egger}, Daniel J. and {Gambella}, Claudio and {Marecek}, Jakub and {McFaddin}, Scott and {Mevissen}, Martin and {Raymond}, Rudy and {Simonetto}, Andrea and {Woerner}, Stefan and {Yndurain}, Elena},\n",
    "        title = \"{Quantum Computing for Finance: State of the Art and Future Prospects}\",\n",
    "      journal = {arXiv e-prints},\n",
    "     keywords = {Quantum Physics, Quantitative Finance - Statistical Finance},\n",
    "         year = 2020,\n",
    "        month = jun,\n",
    "          eid = {arXiv:2006.14510},\n",
    "        pages = {arXiv:2006.14510},\n",
    "archivePrefix = {arXiv},\n",
    "       eprint = {2006.14510},\n",
    " primaryClass = {quant-ph},\n",
    "       adsurl = {https://ui.adsabs.harvard.edu/abs/2020arXiv200614510E},\n",
    "      adsnote = {Provided by the SAO/NASA Astrophysics Data System}\n",
    "}\n",
    "\n",
    "@article{10.2307/2975974,\n",
    " ISSN = {00221082, 15406261},\n",
    " URL = {http://www.jstor.org/stable/2975974},\n",
    " author = {Harry Markowitz},\n",
    " journal = {The Journal of Finance},\n",
    " number = {1},\n",
    " pages = {77--91},\n",
    " publisher = {[American Finance Association, Wiley]},\n",
    " title = {Portfolio Selection},\n",
    " urldate = {2022-12-07},\n",
    " volume = {7},\n",
    " year = {1952}\n",
    "}\n",
    "```"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "pq-dev",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.15 (default, Nov 10 2022, 13:17:42) \n[Clang 14.0.6 ]"
  },
  "orig_nbformat": 4,
  "vscode": {
   "interpreter": {
    "hash": "5fea01cac43c34394d065c23bb8c1e536fdb97a765a18633fd0c4eb359001810"
   }
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
